//
//  LBStatisticsTaskManager.m
//  LBStatistics
//
//  Created by WuShiHai on 19/5/24.
//  Copyright (c) 2019 Lebbay. All rights reserved.
//

#import "LBStatisticsTaskManager.h"
#import "LBStatisticsModel.h"
#import "LBStatisticsTask.h"
#import "LBStatisticsMacros.h"

#define kPageSize 100

@interface LBStatisticsTaskManager ()<LBStatisticsTaskDelegate>

//等待执行的任务,只里面只有type为ad 的，打点统计直接生成task
@property (nonatomic, strong) NSMutableArray *waitingTaskDataArray;

@property (nonatomic, strong) NSMutableArray *taskArray;

@property (nonatomic, strong) dispatch_queue_t dataQueue;

//等待定时器,加入等待队列的任务，不利己执行，登台后面的任务来一起执行
@property (nonatomic, strong) NSTimer *waitingTimer;
@end

@implementation LBStatisticsTaskManager


static LBStatisticsTaskManager *instance = nil;
+ (instancetype)manager{
    if (!instance) {
        instance = [[LBStatisticsTaskManager alloc] init];
    }
    return instance;
}

static void * kDataQueueKey = "LBStatisticsDataQueueKey";
- (instancetype)init{
    self = [super init];
    if (self) {
        _maxSendingCount = 3;
        
        _dataQueue = dispatch_queue_create("StatisticsDataQueue", DISPATCH_QUEUE_SERIAL);
        
        dispatch_queue_set_specific(_dataQueue, kDataQueueKey, (void *)kDataQueueKey, NULL);
        
    }
    return self;
}


- (void)cancelAllTask{
    dispatch_block_t block = ^{
        
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
        for (LBStatisticsTask *task in self.taskArray){
            [task stop];
        }
    };
    
    if (dispatch_get_specific(kDataQueueKey)){
        block();
    }
    else{
        dispatch_async(self.dataQueue, block);
    }
}


- (void)clearTaskForMemoryWarning{
    dispatch_block_t block = ^{
        
        for (int i = 0; i < self.waitingTaskDataArray.count; i++){
            LBStatisticsTaskData *taskData = [self.waitingTaskDataArray objectAtIndex:i];
            if (taskData.taskIdentifier > 0) {
                [self.waitingTaskDataArray removeObjectAtIndex:i];
                i--;
            }
        }
    };
    
    if (dispatch_get_specific(kDataQueueKey)){
        block();
    }
    else{
        dispatch_async(self.dataQueue, block);
    }
}

- (void)addTaskData:(LBStatisticsTaskData *)taskData{
    dispatch_block_t block = ^{
        if (taskData.type == LBStatisticsTaskTypeAd)
        {
            [self addTaskDataToArray:taskData];
        }else{
            //打点统计，没有批处理接口，还是一条条发送
            LBStatisticsTask *task = [[LBStatisticsTask alloc] initWithTaskDatas:@[taskData]];
            task.maxRetryCount = 1;
            [self.taskArray insertObject:task atIndex:0];
            [self startTaskMore];
        }
       
    };
    
    if (dispatch_get_specific(kDataQueueKey)){
        block();
    }
    else{
        dispatch_async(self.dataQueue, block);
    }
}

- (void)addTaskDataToArray:(LBStatisticsTaskData *)taskData{
    if (taskData)
    {
        if (taskData.taskIdentifier <= 0) {
            //放在开头执行,更高优先级
            [self.waitingTaskDataArray insertObject:taskData atIndex:0];
            
        }
        else{
            if (![self isExist:taskData]) {
                [self.waitingTaskDataArray addObject:taskData];
            }
            
        }
        
        
        if (self.waitingTaskDataArray.count < kPageSize) {
            
            dispatch_async(dispatch_get_main_queue(), ^{
                //启动等待定时器
                if (![self.waitingTimer isValid]) {
                    
                    self.waitingTimer = [NSTimer scheduledTimerWithTimeInterval:1
                                                                         target:self
                                                                       selector:@selector(waitingTimeout:)
                                                                       userInfo:nil
                                                                        repeats:NO];
                }
            });
            
            
        }
        else{
            [self startTaskMore];
        }
    }
}

//判断这一条数据，是否已经存在队列中
- (BOOL)isExist:(LBStatisticsTaskData *)oneTaskData{
    for (LBStatisticsTask *task in self.taskArray){
        for (LBStatisticsTaskData *taskData in task.taskDatas){
            if (oneTaskData.taskIdentifier > 0 && oneTaskData.taskIdentifier == taskData.taskIdentifier) {
                return YES;
            }
        }
    }
    return NO;
}

//等待时间到了
- (void)waitingTimeout:(id)timer{
    [self startTaskMore];
}

- (void)startTaskMore{
    
    dispatch_block_t block = ^{
        if ([self sendingCount] < self.maxSendingCount)
        {
            
            NSInteger emptySize = self.maxSendingCount - [self sendingCount];
            
            //从老的task中获取
            if (emptySize > 0) {
                for (int i = 0; i < self.taskArray.count; i++){
                    
                    LBStatisticsTask *task = [self.taskArray objectAtIndex:i];
                    if (task.state == LBStatisticsTaskStateWaiting) {
                        task.delegate = self;
                        [task start];
                        
                        emptySize --;
                        if (emptySize <= 0) {
                            return;
                        }
                    }
                }
            }
            
            
            //从等待队列中生成新的任务来进行
            if (emptySize > 0 ) {
                
                //生成新的task
                NSInteger pageSize = kPageSize;

                for (int i = 0 ; self.waitingTaskDataArray.count > 0 && i < ((self.waitingTaskDataArray.count - 1) / pageSize + 1); i++){
                    NSInteger size = self.waitingTaskDataArray.count - i * pageSize;
                    size = MIN(size, pageSize);
                    NSArray *array = [self.waitingTaskDataArray subarrayWithRange:NSMakeRange(i * pageSize, size)];
                    if (array.count == 0){
                        LBSLog(@"从waitingarray生成task出现错误");
                        return;
                    }
                    LBStatisticsTask *task = [[LBStatisticsTask alloc] initWithTaskDatas:array];
                    task.delegate = self;
                    [task start];
                    LBSLog(@"从waitingarray生成task,并启动");
                    [self.taskArray addObject:task];
                    
                    [self.waitingTaskDataArray removeObjectsInArray:array];
                    i--;
                    
                    emptySize --;
                    if (emptySize <= 0) {
                        return;
                    }
                }
                
                
            }
            
        }
    };
    
    if (dispatch_get_specific(kDataQueueKey)){
        block();
    }
    else{
        dispatch_async(self.dataQueue, block);
    }
}

- (void)removeTask:(LBStatisticsTask *)task{
    if (task) {
        [self.taskArray removeObject:task];
    }
}

#pragma mark - TaskDelegate
//发送成功
- (void)taskSuccess:(LBStatisticsTask *)task{
    dispatch_block_t block = ^{
        LBSLog(@"任务成功 type %ld, url %@ %@",(long)task.type,task.url,task.params?[NSString stringWithFormat:@", params %@",task.params]:@"");
        //根据数据库主键删除数据库中的记录
        
        if (task.type == LBStatisticsTaskTypeAd) {
            
            NSMutableArray *taskDataIDs = [NSMutableArray array];
            for (LBStatisticsTaskData *taskData in task.taskDatas){
                [taskDataIDs addObject:@(taskData.taskIdentifier)];
            }
            [[LBStatisticsModel sharedInstance] removeStatistics:taskDataIDs];
        }
       
        [self removeTask:task];
        //延迟一下，避免http 连续运行阻塞线程
        [self startTaskMore];
    };
    
    if (dispatch_get_specific(kDataQueueKey)){
        block();
    }
    else{
        dispatch_async(self.dataQueue, block);
    }
    
}

//发送失败
- (void)taskFail:(LBStatisticsTask *)task{
    
    dispatch_block_t block = ^{
        LBSLog(@"任务所有重试都失败 type %ld, url %@, params %@",(long)task.type,task.url,task.params);
       
        if (task.type == LBStatisticsTaskTypeAd) {
            [[LBStatisticsModel sharedInstance] updateStatisticsDataFailCount:task.taskDatas];
        }
        
        //更新数据库, 将任务从队列中移除，下次前后台切换的时候重新从db获取，方法@selector(addTaskToArray:)根据failcount升序重新入列
        [self removeTask:task];
        
        [self startTaskMore];
    };
    
    if (dispatch_get_specific(kDataQueueKey)){
        block();
    }
    else{
        dispatch_async(self.dataQueue, block);
    }
    
}

//http失败了一次,入库
- (void)taskFailOne:(LBStatisticsTask *)task error:(NSString *)errorMsg{
    
    dispatch_block_t block = ^{
        LBSLog(@"任务失败一次 type %ld, url %@, param %@",(long)task.type,task.url,task.params);
        /*
        if (task.type == StatisticsTaskTypeAd ) {
            for (StatisticsTaskData *taskData in task.taskDatas){
                if (taskData.type == StatisticsTaskTypeAd && taskData.taskIdentifier <= 0){
                    NSInteger identifier = [[StatisticsModel sharedInstance] insertOneStatistics:taskData];
                    taskData.taskIdentifier = MAX(identifier, 0);
                }
            }
          
        }
         */
        //失败之后，task会等待一定时间再执行
        //所以调用别的任务来执行
        [self startTaskMore];
    };
    
    if (dispatch_get_specific(kDataQueueKey)){
        block();
    }
    else{
        dispatch_async(self.dataQueue, block);
    }
    
}

//任务等待了5s后，准备重新开始任务
- (void)taskWillResend:(LBStatisticsTask*)task{
    
    dispatch_block_t block = ^{
        if ([self sendingCount] < self.maxSendingCount)
        {
            //直接启动,大于时候在别的任务完成一次后在addTask:启动
            if (task.state == LBStatisticsTaskStateWaiting){
                [task start];
            }
        }
    };
    
    if (dispatch_get_specific(kDataQueueKey)){
        block();
    }
    else{
        dispatch_async(self.dataQueue, block);
    }
   
}

#pragma mark - Property

- (NSMutableArray *)taskArray{
    if (_taskArray == nil) {
        _taskArray = [NSMutableArray array];
    }
    return _taskArray;
}

- (NSMutableArray *)waitingTaskDataArray{
    if (_waitingTaskDataArray == nil) {
        _waitingTaskDataArray = [NSMutableArray array];
    }
    return _waitingTaskDataArray;
}

/** 正在运行的任务个数 */
- (NSInteger)sendingCount{
    NSInteger count = 0;
    for (LBStatisticsTask *task in self.taskArray){
        if (task.state == LBStatisticsTaskStateSending) {
            count ++;
        }
    }
    
//    LBSLog(@"正在运行的任务个数 %ld",(long)count);
    return count;
}


//外部任务使用此方法生成一个任务，会讲信息插入数据库
+ (LBStatisticsTaskData *)generateOneTaskData:(NSString *)url params:(NSString *)params type:(LBStatisticsTaskType)type action:(NSString *)action{
    LBStatisticsTaskData *taskData = [[LBStatisticsTaskData alloc] initWithURL:url params:params type:type action:action];
    
    if (type == LBStatisticsTaskTypeAd) {
        //插入数据库
        NSInteger identifier = [[LBStatisticsModel sharedInstance] insertOneStatistics:taskData];
        if (identifier != -1) {
            taskData.taskIdentifier = identifier;
        }
    }
 
    return taskData;
}

@end

